package org.webscale;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.webscale.util.PropertyResolver;
import org.webscale.util.StringUtil;


import javax.servlet.ServletContext;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Properties;

public class ApplicationController {

	private static Logger log = Logger.getLogger(ApplicationController.class);

	// PARAMETERS
	public static final String SPRING_LOCATION = "spring.config";

	public static final String SPRING_LOADER_TYPE = "spring-loader-type";
	
	public static final String SPRING_LOADER_TYPE_FILE = "file";
    public static final String SPRING_LOADER_TYPE_CLASSPATH = "classpath";
	public static final String SPRING_LOADER_TYPE_WEB = "web";
	public static final String APPLICATION_RUN_MODE = "application-run-mode";

	public static final String RUN_MODE_DEFAULT= "test";
	
	
	private Properties startUpParamenters = null;


	private ApplicationContext ac = null;
	
	@SuppressWarnings(value = "unchecked")
	private List systemMessages = new ArrayList();
	private String mode ;

	static ApplicationController self = null;
	static boolean running = false;
	
	
    public static ApplicationController instance(){
    	if(self == null){
    		self = new ApplicationController();
    		running = false;
    	}
    	return self;
    }
	
    public void setRunning(boolean b){
    	running = b;
    }
    
	private ApplicationController(){
    	super();
    }
	
	public Properties getStartUpParamenters() {
		return startUpParamenters;
	}

	public void setStartUpParamenters(Properties startUpParamenters) {
		this.startUpParamenters = startUpParamenters;
	}

	public void setParameter(String key, String value) {
		this.startUpParamenters.put(key, value);
	}

	public String getParameter(String key) {
		return this.startUpParamenters.getProperty(key);
	}

    public void init() {
        init(null);
    }

    public void init(ServletContext context){
		if(running == false){
			if(startUpParamenters ==  null)
				throw new ApplicationException("Start up paramerts not setup" );
			//TODO: FIX this later on RUN Mode set to default
		  mode = startUpParamenters.getProperty(APPLICATION_RUN_MODE);
		  log.info("application run mode " + mode);
		  loadSpring(mode, context);
		  running = true;
		  log.info("init complete....");
		}
		else{
			slog(" Controller already running");
		}
		
		
	}
	 private  void sout(String str){
		   Calendar c =Calendar.getInstance();
		   SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd G 'at' hh:mm:ss z");
		   String dt =df.format(c.getTime());
		   System.out.println("SYSOUT***" +dt + "-" +  ApplicationController.class.getName() + "\t  " + str);
		   systemMessages.add(dt + "-" + str);
	   }
	  private void slog(String str) {
		   sout(str);
		   log.debug(str);
			
		}
	private void loadSpring(String mode, ServletContext context) {
		List springFiles ;
		mode = mode.trim();
		sout("mode = " + mode + " start up param " + startUpParamenters);
		springFiles = (List) PropertyResolver.resolveSequencedProperties(startUpParamenters, mode + "." + "spring.config", 50);
			
		if(springFiles ==  null || springFiles.size() < 1)
		{
			sout("No Spring Files Found , check your start up param , RUN MODE= " + mode );
			throw new ApplicationException("No Spring Files Found , check your start up param , RUN MODE= " + mode);
		}
		sout("MODE = " + mode + " Spring File  = " + springFiles.toString());
		
		String loader = (String) this.startUpParamenters
				.get(SPRING_LOADER_TYPE);
		if (!StringUtil.isValid(loader)) {
			loader = SPRING_LOADER_TYPE_CLASSPATH;
			sout("WARN : spring loader is invalid - " + loader + " Hence trying to load CLASSPATH loader");
		}
		if (springFiles.size() < 1) {
			String[] paths = { "conf/spring-app.xml" };
			slog("WARN : Picking DEFAULT Spring XML at conf/spring/spring-app.xml ");
			ac = new ClassPathXmlApplicationContext(paths);
			return;
		}

		String[] paths = new String[springFiles.size()];
		springFiles.toArray(paths);
		slog("Spring Files in use = " + springFiles);
		if (loader.equals(SPRING_LOADER_TYPE_CLASSPATH)) {
			slog("trying to configure class path based file loader");
			ac = new ClassPathXmlApplicationContext(paths);
		} else if (loader.equals(SPRING_LOADER_TYPE_WEB) && context != null) {
            slog("trying to configure web based file loader");
            ContextLoader contextLoader = new ContextLoader();
            ac = contextLoader.initWebApplicationContext(context);
        } else {
			slog("trying to configure file based classpath ");
			ac = new FileSystemXmlApplicationContext(paths);
		}
		log.info("Seeting the APP CONTEXt in hum = " +ac);
		
	}

	public boolean isRunning() {
		return running;
	}

	public void stop() {
 	 running = false;
	 self = null;
		
	}

	public String getMode() {
		return mode;
	}

	public void setMode(String mode) {
		this.mode = mode;
	}

	public Object locateObject(String name) {
		if(ac == null){
			log.error("Spring is not loaded. TRYNING to use spring before loading it");
			throw new WebsclaeConfigurationException("Spring is not loaded correctly");
		}
		return ac.getBean(name);
	}
	
	public Object locateInterfaceImpl(Class clazz){
		return null;
	}


}
